
require 'Builder'


module ArtOfRails
  module RdfObject #:nodoc:
      
      Namespaces = {
        :rdf => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
        :xsd => 'http://www.w3.org/2001/XMLSchema#'
      }
      
      XsdTypes = {
        :binary => 'http://www.w3.org/2001/XMLSchema#hexBinary', 
        :date => 'http://www.w3.org/2001/XMLSchema#date', 
        :datetime => 'http://www.w3.org/2001/XMLSchema#dateTime', 
        :boolean => 'http://www.w3.org/2001/XMLSchema#boolean', 
        :float => 'http://www.w3.org/2001/XMLSchema#float', 
        :integer => 'http://www.w3.org/2001/XMLSchema#int'        
      }
      
      def self.included(base)
        base.send(:extend, ClassMethods)
        base.send(:include, InstanceMethods)      
        
        # Add a map from class to RDFS Class. 
        base.class_eval do
          class << self
            attr_accessor :rdfs_class_name
            attr_accessor :rdf_method_to_attribute_map
            attr_accessor :rdf_attribute_to_method_map                      
          end

          # todo: Include from super
        end        
        
      end

      # Class Methods For RdfObjects
      module ClassMethods
                
        def rdfs_class(klass)
          self.rdfs_class_name = klass
        end

        def rdf_attribute(variable, rdf_property)
          attr_accessor(variable) 
          self.rdf_method_to_attribute_map = Hash.new if self.rdf_method_to_attribute_map == nil
          self.rdf_attribute_to_method_map = Hash.new if self.rdf_attribute_to_method_map == nil
          self.rdf_method_to_attribute_map[variable] = rdf_property
          self.rdf_attribute_to_method_map[rdf_property] = variable           
        end

      end

      # Class Methods For RdfObjects      
      module InstanceMethods
        
        def rdf_uri
          self.class.rdfs_class_name + '#' + self.object_id.to_s 
        end
        
        #
        # Arguments are an optional Builder::XmlMarkup object followed by
        # an optional hash of options.
        #
        def to_rdf(*args)
          
          # This odd way of inspecting the argument is necessary because instance_eval is 
          # one of the only messages that Builder::XmlMarkup won't turn into an XML tag
          if (args.nil? || args[0].instance_eval { self.class == Hash } )
            builder = Builder::XmlMarkup.new
          else
            builder = args.shift
          end
          
          options = args.shift || {}
          objects_to_append = []
          
          builder.tag!(self.class.rdfs_class_name, { ArtOfRails::RdfObject::Namespaces[:rdf] + ':about' => self.rdf_uri }) do
            self.class.rdf_method_to_attribute_map.each do |method, property|
              val = self.send(method)
              unless (val == nil)
                if (val.is_a? ArtOfRails::RdfObject)
                  objects_to_append << val
                  builder.tag!(property, val.rdf_uri)
                elsif (val.is_a? Array)
                  p 'Printing list'
                else
                  builder.tag!(property, self.send(method))
                end
              end
            end
          end
          
          objects_to_append.each do |obj|
            obj.to_rdf(builder, options)
          end

          builder
        end
      end
      
      module Array
        def to_rdf(builder, options = {})
          raise "Not all elements respond to to_rdf" unless all? { |e| e.respond_to? :to_rdf }
          
          # Implement 
          
        end
        
      end
      
  end
end

Array.send(:include, ArtOfRails::RdfObject::Array)

class Person
  include ArtOfRails::RdfObject
  rdfs_class "http://example.org/Person"  
  rdf_attribute :name, 'http://example.org/Person#name'
  rdf_attribute :pets, 'http://example.org/Person#pet'
end

class Pet
  include ArtOfRails::RdfObject
  rdfs_class "http://example.org/Pet"  
  rdf_attribute :collar, 'http://example.org/Pet#collar'  
  rdf_attribute :name, 'http://example.org/Pet#name'  
end

person = Person.new
person.name = "Ted"

pet = Pet.new
pet.name = "Fido"
pet.collar = true

person.pets = [pet]

builder = Builder::XmlMarkup.new(:indent => 2)

builder = person.to_rdf(builder)
p builder

